package com.tping.lock.deadlock;

import java.util.ArrayList;
import java.util.List;

/**
 * 第二种实现方式：
 * 破坏占用且等待条件
 */
public class DeadLock2 {

    public static void main(String[] args){
        Account acctA = new Account();
        Account acctB = new Account();

        acctA.transfer(acctB, 100);
        acctB.transfer(acctA, 200);
    }

    private static class SingleToHandler{
        private static Allocator INSTANCE = new Allocator();
    }

    public static Allocator getInstance(){
        return SingleToHandler.INSTANCE;
    }

    // 分配器
    static class Allocator{
        private List<Object> als = new ArrayList<>();

        private Allocator(){}

        synchronized boolean apply(Object from , Object to){
            if( als.contains(from) || als.contains(to) ){
                return false;
            }else {
                als.add(from);
                als.add(to);
            }
            return true;
        }

        synchronized void clean(Object from , Object to){
            als.remove(from);
            als.remove(to);
        }
    }

    static class Account{
        private Allocator allocator = DeadLock2.getInstance();

        private int balance;

        void transfer(Account target, int amt){

            // 循环抢占所有资源
            while ( !allocator.apply(this, target) ){}

            try {
                synchronized (this){
                    System.out.println(this.toString() + "obj lock01");
                    synchronized (target){
                        System.out.println(target.toString() + "obj lock02");
                        if( this.balance > amt ){
                            this.balance -= amt;
                            target.balance += amt;
                        }
                    }
                }
            }finally {
                allocator.clean(this, target);
            }
        }
    }
}
